/*
 * Copyright (c)
 *
 * SPDX-License-Identifier: GPL-2.0-only
 *
 * Author:  Juliana Freitag Borin, Flavio Kubota and Nelson L.
 * S. da Fonseca - wimaxgroup@lrc.ic.unicamp.br
 */

#ifndef UL_JOB_H
#define UL_JOB_H

#include "service-flow-record.h"
#include "service-flow.h"
#include "ss-record.h"

#include "ns3/header.h"

#include <stdint.h>

namespace ns3
{

class SSRecord;
class ServiceFlow;

/// Request type enumeration
enum ReqType
{
    DATA,
    UNICAST_POLLING
};

/**
 * @ingroup wimax
 * @brief this class implements a structure to compute the priority of service flows
 */
class UlJob : public Object
{
  public:
    /// Job priority enumeration
    enum JobPriority
    {
        LOW,
        INTERMEDIATE,
        HIGH
    };

    UlJob();
    ~UlJob() override;
    /**
     * Get SS record
     * @returns the SS record
     */
    SSRecord* GetSsRecord() const;
    /**
     * Set SS record
     * @param ssRecord the SS record
     */
    void SetSsRecord(SSRecord* ssRecord);
    /**
     * Get scheduling type
     * @returns the scheduling type
     */
    ServiceFlow::SchedulingType GetSchedulingType() const;
    /**
     * Set scheduling type
     * @param schedulingType the scheduling type
     */
    void SetSchedulingType(ServiceFlow::SchedulingType schedulingType);
    /**
     * Get service flow
     * @returns the service flow
     */
    ServiceFlow* GetServiceFlow() const;
    /**
     * Set service flow
     * @param serviceFlow
     */
    void SetServiceFlow(ServiceFlow* serviceFlow);

    /**
     * Get type
     * @returns the request type
     */
    ReqType GetType() const;
    /**
     * Set type
     * @param type the type
     */
    void SetType(ReqType type);

    /**
     * Get release time
     * @returns the release time
     */
    Time GetReleaseTime() const;
    /**
     * Set release time
     * @param releaseTime the release time
     */
    void SetReleaseTime(Time releaseTime);

    /**
     * Get period
     * @returns the period time
     */
    Time GetPeriod() const;
    /**
     * Set period
     * @param period the period
     */
    void SetPeriod(Time period);

    /**
     * Get deadline
     * @returns the deadline time
     */
    Time GetDeadline() const;
    /**
     * Set deadline
     * @param deadline the dead line
     */
    void SetDeadline(Time deadline);

    /**
     * Get size
     * @returns the size
     */
    uint32_t GetSize() const;
    /**
     * Set size
     * @param size the size
     */
    void SetSize(uint32_t size);

  private:
    /// equality operator
    friend bool operator==(const UlJob& a, const UlJob& b);

    Time m_releaseTime;                           ///< The time after which the job can be processed
    Time m_period;                                ///< For periodic jobs
    Time m_deadline;                              ///< Request should be satisfied by this time
    uint32_t m_size;                              ///< Number of minislots requested
    ServiceFlow::SchedulingType m_schedulingType; ///< Scheduling type of flow

    SSRecord* m_ssRecord; ///< Pointer to SSRecord

    ReqType m_type;             ///< Type of request, DATA or Unicast req slots
    ServiceFlow* m_serviceFlow; ///< service flow
};

/**
 * PriorityUlJob class
 */
class PriorityUlJob : public Object
{
    /**
     * @brief this class implements an auxiliary struct to compute the priority of the rtPS and
     * nrtPS in the intermediate queue
     */
  public:
    PriorityUlJob();
    /**
     * Get priority
     * @returns the priority
     */
    int GetPriority() const;
    /**
     * Set priority
     * @param priority the priority
     */
    void SetPriority(int priority);

    /**
     * Get UL job function
     * @returns the UL job
     */
    Ptr<UlJob> GetUlJob() const;
    /**
     * Set UL job
     * @param job the UL job
     */
    void SetUlJob(Ptr<UlJob> job);

  private:
    int m_priority;   ///< the priority
    Ptr<UlJob> m_job; ///< the job
};

/// SortProcess structure
struct SortProcess
{
    /**
     * @brief comparison operator
     * @param left left side input
     * @param right right side input
     * @returns true if left is logically less then right for given comparison
     */
    bool operator()(PriorityUlJob& left, PriorityUlJob& right) const
    {
        if (left.GetPriority() < right.GetPriority())
        {
            return true;
        }
        else if (left.GetPriority() == right.GetPriority())
        {
            int32_t leftBacklogged =
                left.GetUlJob()->GetServiceFlow()->GetRecord()->GetBacklogged();
            int32_t rightBacklogged =
                left.GetUlJob()->GetServiceFlow()->GetRecord()->GetBacklogged();
            return leftBacklogged <= rightBacklogged;
        }
        else
        {
            return false;
        }
    }
};

/// SortProcessPtr structure
struct SortProcessPtr
{
    /**
     * @brief comparison operator
     * @param left left side input
     * @param right right side input
     * @returns true if left is logically less then right for given comparison
     */
    bool operator()(Ptr<PriorityUlJob>& left, Ptr<PriorityUlJob>& right) const
    {
        if (left->GetPriority() < right->GetPriority())
        {
            return true;
        }
        else if (left->GetPriority() == right->GetPriority())
        {
            int32_t leftBacklogged =
                left->GetUlJob()->GetServiceFlow()->GetRecord()->GetBacklogged();
            int32_t rightBacklogged =
                left->GetUlJob()->GetServiceFlow()->GetRecord()->GetBacklogged();
            return leftBacklogged <= rightBacklogged;
        }
        else
        {
            return false;
        }
    }
};

} // namespace ns3

#endif /* UL_JOB_H */
